import sys
import traceback
import json
from redis import Redis
from sqlalchemy.orm import Session
from sqlalchemy.sql import func
from app.models import PayOrder
from app.common import enums
from app.common.enums import OrderStatus

from app.common.exceptions import GenericException
from app.common.enums import ErrTypes
from app import utils
from app.config import conf
from app.models.trans_data import CardDailyTransData, CardMonthlyTransData

import logging
logger = logging.getLogger(__name__)

CACHE_KEY = 'card_data'
DAY_EX_SECONDS = 60 * 60 * 24 * 2   # 2天
MONTH_EX_SECONDS = 60 * 60 * 24 * 60 # 2个月\
LIMIT_TRANS_AMOUNT = int(conf.LIMIT_TRANS_AMOUNT)
LIMIT_DAY_AMOUNT = int(conf.LIMIT_DAY_AMOUNT)
LIMIT_MONTH_AMOUNT = int(conf.LIMIT_MONTH_AMOUNT)

##################### 卡交易数据 ####################


def get_card_day_cache_data(db: Session, r: Redis, card_no, amount):
    logger.info('>> get_card_day_cache_data')
    trans_date = utils.get_time_now(type=5)
    key = f'{CACHE_KEY}:day:{card_no}:{trans_date}'
    day_data = {}
    data_js = r.get(key)
    if data_js:
        day_data = json.loads(data_js)
        new_amount = day_data.get('amount') + amount
        if new_amount > LIMIT_DAY_AMOUNT:
            logger.error(f'单卡日交易超过限额')
            raise GenericException(ErrTypes.acc_no_enough_balance)
        else:
            return True
    else:
        return True

def get_card_trans_date_data(db: Session, card_no, trans_date):
    return db.query(CardDailyTransData).filter(
        CardDailyTransData.card_no == card_no,
        CardDailyTransData.trans_date == trans_date).first()

def get_card_trans_month_data(db: Session, card_no, trans_month):
    return db.query(CardMonthlyTransData).filter(
        CardMonthlyTransData.card_no == card_no,
        CardMonthlyTransData.trans_month == trans_month).first()

################## 缓存数据累加 #####################
CACHE_KEY = 'card_data'
DAY_EX_SECONDS = 60 * 60 * 24 * 2   # 2天
MONTH_EX_SECONDS = 60 * 60 * 24 * 60 # 2个月

def cache_card_trans_date_data(r: Redis, new_order: PayOrder) -> CardDailyTransData:
    logger.info('>> 缓存卡日交易数据')
    try:
        trans_date = utils.fmt_time(new_order.create_time, type=5)
        key = f'{CACHE_KEY}:day:{trans_date}'
        day_data = {}
        data_js = r.get(key)
        if data_js:
            day_data = json.loads(data_js)
            day_data['amount'] += new_order.amount
        else:
            day_data['card_no'] = new_order.card_no
            day_data['amount'] = new_order.amount
            day_data['bank_code'] = new_order.bank_code
            day_data['account_type'] = new_order.account_type
            day_data['trans_date'] = new_order.trans_date
        r.set(key, day_data)
        return day_data
    except GenericException as err:
        logger.error(err.message)
        raise GenericException(err.error_type, message=err.message, data=err.data)
    except Exception as err:
        logger.error('缓存卡日交易数据失败')
        exc_type, exc_value, exc_obj = sys.exc_info()
        traceback.print_exception(exc_type,exc_value,exc_obj,limit=3,file=sys.stdout)
        raise GenericException(ErrTypes.chn_trans_error)

def cache_card_trans_month_data(r: Redis, new_order: PayOrder) -> CardDailyTransData:
    logger.info('>> 缓存卡月交易数据')
    try:
        trans_date = utils.fmt_time(new_order.create_time, type=6)
        key = f'{CACHE_KEY}:day:{trans_date}'
        day_data = {}
        data_js = r.get(key)
        if data_js:
            day_data = json.loads(data_js)
            day_data['amount'] += new_order.amount
        else:
            day_data['card_no'] = new_order.card_no
            day_data['amount'] = new_order.amount
            day_data['bank_code'] = new_order.bank_code
            day_data['account_type'] = new_order.account_type
            day_data['trans_date'] = new_order.trans_date
        r.set(key, day_data)
        return day_data
    except GenericException as err:
        logger.error(err.message)
        raise GenericException(err.error_type, message=err.message, data=err.data)
    except Exception as err:
        logger.error('缓存卡月交易数据失败')
        exc_type, exc_value, exc_obj = sys.exc_info()
        traceback.print_exception(exc_type,exc_value,exc_obj,limit=3,file=sys.stdout)
        raise GenericException(ErrTypes.chn_trans_error)


################### DB数据累加 #####################

def add_card_trans_date_data(db: Session, r: Redis, new_order: PayOrder) -> CardDailyTransData:
    logger.info('>> 添加卡日交易数据')
    try:
        trans_date = utils.fmt_time(new_order.create_time, type=5)
        card_day_data = get_card_trans_date_data(db, new_order.card_no, trans_date)
        if card_day_data:
            logger.info('累积日交易数据记录')
            card_day_data.amount += new_order.amount
        else:
            logger.info('暂无日交易数据记录，新建...')
            card_day_data = CardDailyTransData()
            card_day_data.card_no = new_order.card_no,
            card_day_data.amount = new_order.amount,
            card_day_data.bank_code = new_order.bank_code
            card_day_data.account_type = new_order.account_type
            card_day_data.trans_date = trans_date  
        db.add(card_day_data)
        db.commit()
        db.refresh(card_day_data)
        return card_day_data
    except GenericException as err:
        logger.error(err.message)
        raise GenericException(err.error_type, message=err.message, data=err.data)
    except Exception as err:
        logger.error('添加卡日交易数据失败')
        exc_type, exc_value, exc_obj = sys.exc_info()
        traceback.print_exception(exc_type,exc_value,exc_obj,limit=3,file=sys.stdout)
        raise GenericException(ErrTypes.chn_trans_error)
    

def add_card_trans_month_data(db: Session, new_order: PayOrder) -> CardMonthlyTransData:
    logger.info('>> 添加卡月交易数据')
    try:
        trans_month = utils.fmt_time(new_order.create_time, type=6)
        card_month_data = get_card_trans_month_data(db, new_order.card_no, trans_month)
        if card_month_data:
            logger.info('累积月交易数据记录')
            card_month_data.amount += new_order.amount
        else:
            logger.info('暂无月交易数据记录，新建...')
            card_month_data = CardMonthlyTransData()
            card_month_data.card_no = new_order.card_no,
            card_month_data.amount = new_order.amount,
            card_month_data.bank_code = new_order.bank_code
            card_month_data.account_type = new_order.account_type
            card_month_data.trans_month = trans_month  
        db.add(card_month_data)
        db.commit()
        db.refresh(card_month_data)
        return card_month_data
    except GenericException as err:
        logger.error(err.message)
        raise GenericException(err.error_type, message=err.message, data=err.data)
    except Exception as err:
        logger.error('添加卡月交易数据失败')
        exc_type, exc_value, exc_obj = sys.exc_info()
        traceback.print_exception(exc_type,exc_value,exc_obj,limit=3,file=sys.stdout)
        raise GenericException(ErrTypes.chn_trans_error)
    
